package mbsl.ui.dialogs;

import static mbsl.util.SWTUtils.Direction.down;
import static mbsl.util.SWTUtils.Direction.left;
import static mbsl.util.SWTUtils.Direction.right;
import static mbsl.util.SWTUtils.Direction.up;
import mbsl.system.Core;
import mbsl.system.TextProvider;
import mbsl.util.SWTUtils;

import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.ShellAdapter;
import org.eclipse.swt.events.ShellEvent;
import org.eclipse.swt.layout.FormLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;

/**
 * An abstract dialog which serves as the template for all the custom dialogs in Dialogs.
 * <p>
 * Out of the box, it has a window, a title, a message, an OK button, and a cancel button.  Extending classes can
 * add components in the {@link #addComponents(Shell, Label, Button)} method.
 *
 * @param <T> The class of the object the dialog will return.
 */
public abstract class Dialog<T> {
	private static TextProvider tp = Core.tp;
	
	protected Dialog(Shell pParent, String pMessage, String pHeader) {
		mWindow = new Shell(pParent, SWT.DIALOG_TRIM | SWT.APPLICATION_MODAL);
		
		mWindow.setLayout(new FormLayout());
		mWindow.setText(pHeader);
		mWindow.addShellListener(new ShellAdapter() {
			public void shellClosed(ShellEvent pE) {
				close(null);
			}
		});
		// Information label
		Label label = new Label(mWindow, SWT.NONE);
		
		label.setLayoutData(SWTUtils.getFormData(
				SWTUtils.getMeta(left, 0, 5),
				SWTUtils.getMeta(right, 100, -5),
				SWTUtils.getMeta(up, 0, 5)
		));
		label.setText(pMessage);
		label.setFont(SWTUtils.getBold(label.getFont()));
		// Cancel button
		Button cancel = new Button(mWindow, SWT.PUSH);
		
		cancel.setLayoutData(SWTUtils.getFormData(
				SWTUtils.getMeta(down, 100, -2),
				SWTUtils.getMeta(right, 100, -2)
		));
		cancel.setText(tp.get("ui.cancel"));
		cancel.addSelectionListener(new SelectionAdapter() {
			public void widgetSelected(SelectionEvent pE) {
				close(null);
			}
		});
		// OK button
		Button confirm = new Button(mWindow, SWT.PUSH);
		
		confirm.setLayoutData(SWTUtils.getFormData(cancel.computeSize(SWT.DEFAULT, SWT.DEFAULT).x, SWT.DEFAULT, 
				SWTUtils.getMeta(down, 100, -2),
				SWTUtils.getMeta(right, cancel, -2)
		));
		confirm.setText(tp.get("ui.ok"));

		addComponents(mWindow, label, confirm);
	}
	
	/**
	 * Opens the dialog.
	 * <p>
	 * Note that this method will block until the dialog is closed
	 * @return The response, or null if the dialog was cancelled or closed.
	 */
	T open() {
		mWindow.pack();

		mWindow.setVisible(true);
		
		SWTUtils.block(mWindow);
		
		return mResponse;
	}
	protected void close(T pResponse) {
		mResponse = pResponse;
		
		mWindow.dispose();
	}
	/** 
	 * Calls for the children to add their components.
	 * <p>
	 * The label has a 5 pixel margin on each side.  The OK and Cancel buttons have a 2 pixel margin on each side, including between them.
	 * @param window The Shell to add components to.
	 * @param label The label showing the message text.  Provided mainly for other components to use for orientation.
	 * @param confirm The OK button.
	 */
	protected abstract void addComponents(Shell window, Label label, Button confirm);
	
	private T mResponse;
	private Shell mWindow;
}
